home *** CD-ROM | disk | FTP | other *** search
/ A.C.E. 2 / ACE CD 2.iso / FILES / UTILS / GAMESDS2.DMS / in.adf / GDS_Tutorial.lha / Examples / parallax / pdemo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-15  |  20.8 KB  |  596 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <exec/memory.h>
  5. #include <exec/types.h>
  6. #include <graphics/gfx.h>
  7. #include <graphics/gfxbase.h>
  8.  
  9. #include <proto/exec.h>
  10. #include <proto/graphics.h>
  11. #include <proto/intuition.h>
  12.  
  13. #include "GameSmith:GameSmith.h"
  14. #include "GameSmith:include/libraries/libptrs.h"
  15.  
  16. #define PVP_FIELDS   8      /* 7 parallax viewport fields */
  17. #define CLOUDS         5      /* 1st 5 parallax fields are clouds */
  18. #define SPVP_HEIGHT   40      /* height of bottom field */
  19. #define COLOR_STEPS   26      /* number of color changes to background */
  20. #define SCROLL_SPEED   2      /* number of pixels to scroll foreground playfield */
  21. #define BOTTOM_SPEED 8      /* scroll speed at bottom of display */
  22.  
  23. #define SHEIGHT   200      /* screen height */
  24. #define SWIDTH      320      /* screen width */
  25.  
  26. /*-------------------------------------------------------------------------*/
  27. /* Function Prototypes                                                      */
  28.  
  29. void scan_copper(void);
  30.  
  31. int setup(void);
  32. int load_gfx(void);
  33. void build_copper(void);
  34. void user_input(void);
  35. int check_close(void);
  36. void cleanup(void);
  37. void dealloc(void);
  38.  
  39. /*-------------------------------------------------------------------------*/
  40. /* some global variables                                                   */
  41.  
  42. int smode,copheight=200,red=16,green=96,blue=255,chipset,left,right;
  43.  
  44. unsigned char cloud_move[CLOUDS]={1,1,1,1,1};
  45. unsigned char cloud_rate[CLOUDS]={0,1,2,3,4};
  46. unsigned char cloud_count[CLOUDS]={0,0,0,0,0};
  47.  
  48. unsigned short copper_list[2048];
  49.  
  50. unsigned long color[PVP_FIELDS][8];
  51.  
  52. unsigned char *pic_names[]={         /* names of gfx files to load */
  53.    "gfx/cloud1.brush",
  54.    "gfx/cloud2.brush",
  55.    "gfx/cloud3.brush",
  56.    "gfx/cloud4.brush",
  57.    "gfx/cloud5.brush",
  58.    "gfx/mtn.brush",
  59.    "gfx/fence.brush",
  60.    "gfx/marsh.brush"
  61.    };
  62.  
  63. BitMapHeader bmh;
  64.  
  65. struct loadILBM_struct loadpic =
  66.    {
  67.    NULL,               /* ptr to picture name string */
  68.    NULL,               /* ptr to 1st bitmap */
  69.    NULL,               /* ptr to 2nd bitmap (if any) */
  70.    NULL,               /* ptr to color table array */
  71.    0,                  /* # colors in color table */
  72.    NULL,               /* height of image in pixels (filled by load call) */
  73.    NULL,               /* width of image in pixels (filled) */
  74.    NULL,               /* x display offset (filled) */
  75.    NULL,               /* y display offset (filled) */
  76.    NULL,               /* pic mode (filled) */
  77.    0,                  /* x load offset (from left) in bytes */
  78.    0,                  /* y load offset (from top) in rows */
  79.    ILBM_COLOR|ILBM_ALLOC1,   /* flags (fill color table, alloc 1 bitmap) */
  80.    0xff,               /* bitplane fill mask */
  81.    0xff,               /* bitplane load mask */
  82.    &bmh               /* address of BitMapHeader to fill */
  83.    };
  84.  
  85. struct gs_pvp pvp[PVP_FIELDS-1];
  86.  
  87. long scolor[8*SPVP_HEIGHT];
  88. unsigned short clist[]={0,9,10,11,12,13,14,15};      /* color reg list for reload */
  89.  
  90. struct gs_spvp spvp =         /* sliced parallax viewport */
  91.    {
  92.    1,3,                        /* top & bottom scroll rates */
  93.    0,0,0,                     /* height, width, depth */
  94.    PVP_DPF|PVP_DPF2,          /* flags (dual playfield, only load & scroll pf2) */
  95.    NULL,NULL,                  /* ptr to bitmap(s) */
  96.    NULL,                        /* ptr to color table of values to modify each line */
  97.    clist,                     /* ptr to list of regs to modify each line */
  98.    8,                           /* number of regs in list */
  99.    0,                           /* scroll type */
  100.    0,0,                        /* system stuff */
  101.    NULL                        /* no parallax viewports in list yet */
  102.    };
  103.  
  104. struct gs_spvp spvp2 =         /* sliced parallax viewport */
  105.    {
  106.    3,BOTTOM_SPEED,            /* top & bottom scroll rates */
  107.    0,0,0,                     /* height, width, depth */
  108.    PVP_DPF|PVP_DPF2,          /* flags (dual playfield, only load & scroll pf2) */
  109.    NULL,NULL,                  /* ptr to bitmap(s) */
  110.    NULL,                        /* ptr to color table of values to modify each line */
  111.    clist,                     /* ptr to list of regs to modify each line */
  112.    8,                           /* number of regs in list */
  113.    0,                           /* scroll type */
  114.    0,0,                        /* system stuff */
  115.    NULL                        /* no parallax viewports in list yet */
  116.    };
  117.  
  118. unsigned long fore_color[8];
  119.  
  120. struct gs_viewport vp =
  121.    {
  122.    NULL,                           /* ptr to next viewport */
  123.    fore_color,                     /* ptr to color table */
  124.    8,                              /* number of colors in table */
  125.    copper_list,                  /* ptr to user copper list (none) */
  126.    SHEIGHT,SWIDTH,6,0,0,         /* height, width, depth, bmheight, bmwidth */
  127.    0,0,                           /* top & left viewport offsets */
  128.    0,0,                           /* X & Y bitmap offsets */
  129.    GSVP_DPF|GSVP_NOWAIT,         /* flags */
  130.    NULL,NULL,                     /* 2.xx & above compatibility stuff */
  131.    NULL,NULL,                     /* bitmap pointers */
  132.    NULL,                           /* future expansion */
  133.    0,0,0,0                        /* display clip (use nominal) */
  134.    };
  135.  
  136. struct display_struct display =
  137.    {
  138.    NULL,                           /* ptr to previous display view */
  139.    NULL,NULL,                     /* 2.xx & above compatibility stuff */
  140.    0,0,                           /* X and Y display offsets (1.3 style) */
  141.    0,                              /* display mode ID */
  142.    4,4,                           /* sprite priorities (sprites in front of playfields) */
  143.    GSV_SCROLLABLE|GSV_HARDX|     /* flags (double buffered, scrollable, hard X, */
  144.    GSV_BRDRBLNK,                  /* blank borders) */
  145.    &vp,                           /* ptr to 1st viewport */
  146.    NULL                           /* future expansion */
  147.    };
  148.  
  149. /***************************************************************************/
  150.  
  151. main(argc,argv)
  152. int argc;
  153. char *argv[];
  154.  
  155. {
  156.    int err,end=0;
  157.  
  158.    if (gs_open_libs(DOS|GRAPHICS,0))   /* open AmigaDOS libs */
  159.       exit(01);               /* if can't open libs, abort */
  160.    if (err=setup())            /* if couldn't get set up... abort program */
  161.       {
  162.       printf("\nSetup error: %d\n",err);
  163.       gs_close_libs();         /* close all libraries */
  164.       exit(02);
  165.       }
  166.    Forbid();                  /* take over the entire machine */
  167.    while (!end)               /* this shows off speed */
  168.       {
  169.       user_input();            /* check user input & handle it */
  170.       end=check_close();      /* end when user hits left mouse button */
  171.       }
  172.    Permit();                  /* OK, let other things run while we clean up */
  173.    cleanup();                  /* close & deallocate everything */
  174.    gs_close_libs();            /* close all libraries */
  175. }
  176.  
  177. /***************************************************************************/
  178.  
  179. int setup()
  180.  
  181. {
  182.    smode=0;               /* default mode of lores no lace, dual playfield */
  183.    #ifdef NTSC_MONITOR_ID
  184.       if (GfxBase->LibNode.lib_Version >= 36)   /* if WB 2.0 or higher */
  185.          {               /* this defeats mode promotion on AGA machines */
  186.          /* hardware doesn't allow dual playfield under double scanned display */
  187.          if (ModeNotAvailable(NTSC_MONITOR_ID))
  188.             {
  189.             smode = PAL_MONITOR_ID;
  190.             }
  191.          else
  192.             {
  193.             smode = NTSC_MONITOR_ID;
  194.             }
  195.          }
  196.    #endif
  197.    chipset=gs_chiprev();
  198.    switch (chipset)         /* set hard left display offset depending on chipset */
  199.       {
  200.       case AGA_CHIPREV:
  201.          if (GfxBase->LibNode.lib_Version >= 36)   /* if WB 2.0 or higher */
  202.             display.DxOffset=0x85;
  203.          else
  204.             display.DxOffset=0;
  205.          break;
  206.       default:
  207.          if (GfxBase->LibNode.lib_Version >= 36)   /* if WB 2.0 or higher */
  208.             display.DxOffset=0x77;
  209.          else
  210.             display.DxOffset=0;
  211.          left=0x39;
  212.          right=0xdf;
  213.          break;
  214.       }
  215.    if (load_gfx())
  216.       {
  217.       dealloc();
  218.       printf("\nError loading graphics\n");
  219.       return(-1);
  220.       }
  221.    if (gs_alloc_spvp(&spvp))
  222.       {
  223.       dealloc();
  224.       printf("\nInsufficient Memory for Sliced Parallax Viewport\n");
  225.       return(-2);
  226.       }
  227.    if (gs_alloc_spvp(&spvp2))
  228.       {
  229.       printf("\nInsufficient Memory for Sliced Parallax Viewport\n");
  230.       dealloc();
  231.       return(-3);
  232.       }
  233.    display.modes = smode;
  234.    build_copper();
  235.    if (gs_create_display(&display))
  236.       {
  237.       dealloc();
  238.       printf("\nUnable to Set Up Display\n");
  239.       return(-3);
  240.       }
  241.    gs_open_vb_timer();
  242.    gs_show_display(&display,1);      /* show display, sync */
  243.    return(0);
  244. }
  245.  
  246. /***************************************************************************/
  247.  
  248. int load_gfx()
  249.  
  250. {
  251.    int cnt,cnt2,cnt3=0,r,g,b;
  252.    static struct BitMap bm;
  253.  
  254.    loadpic.file="gfx/forest.brush";      /* name of file to load */
  255.    loadpic.color_table=fore_color;      /* ptr to color table to fill */
  256.    loadpic.num_colors=8;               /* each field is 3 bitplanes deep maximum */
  257.    if (gs_loadILBM(&loadpic))
  258.       {
  259.       return(-1);
  260.       }
  261.    vp.bitmap1=loadpic.bitmap1;
  262.    vp.bitmap1->Planes[5]=vp.bitmap1->Planes[0];
  263.    vp.bitmap1->Planes[4]=vp.bitmap1->Planes[2];   /* readjust for dual playfield */
  264.    vp.bitmap1->Planes[3]=vp.bitmap1->Planes[0];
  265.    vp.bitmap1->Planes[2]=vp.bitmap1->Planes[1];
  266.    vp.bitmap1->Depth=6;
  267.    vp.bmwidth=bmh.w;                     /* actual width of bitmap */
  268.    for (cnt=0; cnt < PVP_FIELDS; cnt++)
  269.       {
  270.       loadpic.file=pic_names[cnt];         /* name of file to load */
  271.       loadpic.color_table=&color[cnt][0];   /* ptr to color table to fill */
  272.       loadpic.num_colors=8;               /* each field is 3 bitplanes deep maximum */
  273.       if (gs_loadILBM(&loadpic))
  274.          {
  275.          return(-1);
  276.          }
  277.       if ((cnt+1) < PVP_FIELDS)
  278.          {
  279.          pvp[cnt].bitmap[0]=loadpic.bitmap1;
  280.          pvp[cnt].bitmap[1]=loadpic.bitmap1;
  281.          pvp[cnt].depth=loadpic.bitmap1->Depth;
  282.          pvp[cnt].height=bmh.h;
  283.          pvp[cnt].width=bmh.w;
  284.          pvp[cnt].flags=PVP_DPF|PVP_DPF2;
  285.          }
  286.       else                                 /* last field is the sliced parallax viewport */
  287.          {                                 /* we need to split it & squeeze in fence reload */
  288.          spvp.bitmap[0]=loadpic.bitmap1;
  289.          spvp.bitmap[1]=loadpic.bitmap1;
  290.          spvp.depth=loadpic.bitmap1->Depth;
  291.          spvp.height=14;
  292.          spvp.width=bmh.w;
  293.          bm.Depth=loadpic.bitmap1->Depth;   /* pick up where previous spvp left off */
  294.          bm.Flags=loadpic.bitmap1->Flags;   /* (continue spvp below top of fence) */
  295.          bm.Rows=25;                        /* 40 - height1 - 1 line for fence load */
  296.          bm.BytesPerRow=loadpic.bitmap1->BytesPerRow;
  297.          bm.Planes[0]=loadpic.bitmap1->Planes[0]+(bm.BytesPerRow*15);
  298.          bm.Planes[1]=loadpic.bitmap1->Planes[1]+(bm.BytesPerRow*15);
  299.          bm.Planes[2]=loadpic.bitmap1->Planes[2]+(bm.BytesPerRow*15);
  300.          bm.Planes[3]=loadpic.bitmap1->Planes[3]+(bm.BytesPerRow*15);
  301.          bm.Planes[4]=loadpic.bitmap1->Planes[4]+(bm.BytesPerRow*15);
  302.          bm.Planes[5]=loadpic.bitmap1->Planes[5]+(bm.BytesPerRow*15);
  303.          bm.Planes[6]=loadpic.bitmap1->Planes[6]+(bm.BytesPerRow*15);
  304.          bm.Planes[7]=loadpic.bitmap1->Planes[7]+(bm.BytesPerRow*15);
  305.          spvp2.bitmap[0]=&bm;
  306.          spvp2.bitmap[1]=&bm;
  307.          spvp2.depth=loadpic.bitmap1->Depth;
  308.          spvp2.height=25;
  309.          spvp2.width=bmh.w;
  310.          }
  311.       }
  312.    pvp[PVP_FIELDS-2].flags = PVP_DPF|PVP_DPF1;   /* fence is in playfield 1 (foreground) */
  313.    spvp.ctable=(unsigned long *)scolor;   /* pointer to color table */
  314.    spvp2.ctable=(unsigned long *)&scolor[15*8];
  315.    for (cnt=0; cnt < SPVP_HEIGHT; cnt++)   /* dim the grass color from bottom to top */
  316.       {
  317.       for (cnt2=0; cnt2 < 8; cnt2++)
  318.          {
  319.          r=(color[PVP_FIELDS-1][cnt2]>>20)&0x0f;
  320.          g=(color[PVP_FIELDS-1][cnt2]>>12)&0x0f;
  321.          b=(color[PVP_FIELDS-1][cnt2]>>4)&0x0f;
  322.          r-=cnt/6;
  323.          g-=cnt/6;
  324.          b-=cnt/6;
  325.          if (r < 0)
  326.             r=0;
  327.          if (g < 0)
  328.             g = 0;
  329.          if (b < 0)
  330.             b=0;
  331.          scolor[cnt3++]=(r<<20)|(g<<12)|(b<<4);
  332.          }
  333.       }
  334.    return(0);
  335. }
  336.  
  337. /***************************************************************************/
  338. /* NOTE: The AGA and ECS chipset can blank the border area, but the OCS
  339.    chipset cannot.  In this case, we must turn color 0 on and off every line
  340.    in sync with the display window (sigh). */
  341.  
  342. void build_copper()
  343.  
  344. /* build a custom copper list of background color changes */
  345.  
  346. {
  347.    int cnt,cnt2=0,top=0,cnt3=0,cnt4,height,change=0;
  348.    unsigned char line=0,do_color=0;
  349.    struct BitMap *bm;
  350.  
  351.    height=SHEIGHT-spvp.height-spvp2.height-1; /* height of copper background color change area */
  352.    copper_list[cnt2++]=UC_PVP;         /* add parallax viewport */
  353.    copper_list[cnt2++]=top;            /* y coord to wait on */
  354.    copper_list[cnt2++]=(unsigned long)&pvp[cnt3]>>16;   /* address of parallax viewport */
  355.    copper_list[cnt2++]=(unsigned short)&pvp[cnt3];
  356.    if (chipset == OCS_CHIPREV)         /* delay if OCS */
  357.       {                                 /* need to sync with left of display */
  358.       copper_list[cnt2++]=UC_WAIT;
  359.       copper_list[cnt2++]=0;            /* y coord to wait on */   
  360.       copper_list[cnt2++]=left;         /* x coord */
  361.       }
  362.    copper_list[cnt2++]=UC_SETCOLOR;
  363.    copper_list[cnt2++]=0;
  364.    copper_list[cnt2++]=((red&0xf0)<<4)|(green&0xf0)|((blue&0xf0)>>4);
  365.    bm=pvp[cnt3].bitmap[0];
  366.    for (cnt=1; cnt < (1<<bm->Depth); cnt++)
  367.       {
  368.       copper_list[cnt2++]=UC_SETCOLOR;
  369.       copper_list[cnt2++]=cnt+8;
  370.       copper_list[cnt2++]=((color[cnt3][cnt]>>12)&0x0f00)|((color[cnt3][cnt]>>8)&0x00f0)|
  371.          ((color[cnt3][cnt]>>4)&0x0f);   /* 24 bit color value to old 12 bit color value */
  372.       }
  373.    top+=pvp[cnt3++].height;
  374.    for (cnt4=0; cnt4 < height; cnt4++)
  375.       {
  376.       if (change > (height/COLOR_STEPS))
  377.          {
  378.          change=0;
  379.          line++;
  380.          if (line < 15)
  381.             {
  382.             red+=16;
  383.             blue-=16;
  384.             }
  385.          else
  386.             {
  387.             green+=16;
  388.             }
  389.          do_color=1;
  390.          }
  391.       change++;
  392.       if (cnt4 == top) /* a PVP event *MUST* come before anything else on the line!!!! */
  393.          {
  394.          copper_list[cnt2++]=UC_PVP;      /* add parallax viewport */
  395.          copper_list[cnt2++]=top;         /* y coord to wait on */
  396.          copper_list[cnt2++]=(unsigned long)&pvp[cnt3]>>16;   /* address of parallax viewport */
  397.          copper_list[cnt2++]=(unsigned short)&pvp[cnt3];
  398.          if (chipset == OCS_CHIPREV)      /* delay if OCS */
  399.             {                              /* need to sync with left of display */
  400.             copper_list[cnt2++]=UC_WAIT;
  401.             copper_list[cnt2++]=cnt4;      /* y coord to wait on */   
  402.             copper_list[cnt2++]=left;      /* x coord */
  403.             }
  404.          copper_list[cnt2++]=UC_SETCOLOR;
  405.          copper_list[cnt2++]=0;
  406.          copper_list[cnt2++]=((red&0xf0)<<4)|(green&0xf0)|((blue&0xf0)>>4);
  407.          bm=pvp[cnt3].bitmap[0];
  408.          for (cnt=1; cnt < (1<<bm->Depth); cnt++)
  409.             {
  410.             copper_list[cnt2++]=UC_SETCOLOR;
  411.             copper_list[cnt2++]=cnt+8;
  412.             copper_list[cnt2++]=((color[cnt3][cnt]>>12)&0x0f00)|((color[cnt3][cnt]>>8)&0x00f0)|
  413.                ((color[cnt3][cnt]>>4)&0x0f);   /* 24 bit color value to old 12 bit color value */
  414.             }
  415.          top+=pvp[cnt3++].height;
  416.          }
  417.       else
  418.          {
  419.          switch (chipset)
  420.             {
  421.             case AGA_CHIPREV:         /* borders are blanked under AGA/ECS, so don't worry */
  422.             case ECS_CHIPREV:       /* about color 0 overrun in border. :) */
  423.                if (do_color)
  424.                   {
  425.                   copper_list[cnt2++]=UC_WAIT;
  426.                   copper_list[cnt2++]=cnt4;         /* y coord to wait on */   
  427.                   copper_list[cnt2++]=0;            /* x coord */
  428.                   }
  429.                break;
  430.             default:                  /* for OCS, need to turn background color */
  431.                do_color=1;            /* on & off at start & end of each line! (ugh) */
  432.                copper_list[cnt2++]=UC_WAIT;
  433.                copper_list[cnt2++]=cnt4;         /* y coord to wait on */   
  434.                copper_list[cnt2++]=left;         /* x coord */
  435.                break;
  436.             }
  437.          if (do_color)
  438.             {
  439.             copper_list[cnt2++]=UC_SETCOLOR;
  440.             copper_list[cnt2++]=0;
  441.             copper_list[cnt2++]=((red&0xf0)<<4)|(green&0xf0)|((blue&0xf0)>>4);
  442.             do_color=0;
  443.             }
  444.          }
  445.       if (chipset == OCS_CHIPREV)
  446.          {
  447.          copper_list[cnt2++]=UC_WAIT;
  448.          copper_list[cnt2++]=cnt4;         /* y coord to wait on */   
  449.          copper_list[cnt2++]=right;         /* x coord */
  450.          copper_list[cnt2++]=UC_SETCOLOR;
  451.          copper_list[cnt2++]=0;
  452.          copper_list[cnt2++]=0;
  453.          }
  454.       }
  455.    copper_list[cnt2++]=UC_SPVP;      /* add sliced parallax viewport */
  456.    copper_list[cnt2++]=top;         /* y coord to wait on */
  457.    copper_list[cnt2++]=(unsigned long)&spvp>>16;   /* address of parallax viewport */
  458.    copper_list[cnt2++]=(unsigned short)&spvp;
  459.    top+=spvp.height;
  460.    copper_list[cnt2++]=UC_PVP;      /* add parallax viewport */
  461.    copper_list[cnt2++]=top;         /* y coord to wait on */
  462.    copper_list[cnt2++]=(unsigned long)&pvp[cnt3]>>16;   /* address of parallax viewport */
  463.    copper_list[cnt2++]=(unsigned short)&pvp[cnt3];
  464.    bm=pvp[cnt3].bitmap[0];
  465.    for (cnt=1; cnt < (1<<bm->Depth); cnt++)
  466.       {
  467.       copper_list[cnt2++]=UC_SETCOLOR;
  468.       copper_list[cnt2++]=cnt;
  469.       copper_list[cnt2++]=((color[cnt3][cnt]>>12)&0x0f00)|((color[cnt3][cnt]>>8)&0x00f0)|
  470.          ((color[cnt3][cnt]>>4)&0x0f);   /* 24 bit color value to old 12 bit color value */
  471.       }
  472.    top+=1;
  473.    copper_list[cnt2++]=UC_SPVP;      /* add sliced parallax viewport */
  474.    copper_list[cnt2++]=top;         /* y coord to wait on */
  475.    copper_list[cnt2++]=(unsigned long)&spvp2>>16;   /* address of parallax viewport */
  476.    copper_list[cnt2++]=(unsigned short)&spvp2;
  477.    copper_list[cnt2++]=UC_SETCOLOR;
  478.    copper_list[cnt2++]=0;
  479.    copper_list[cnt2++]=0;
  480.    copper_list[cnt2++]=UC_END;      /* end coppper list */
  481. }
  482.  
  483. /***************************************************************************/
  484.  
  485. void user_input()
  486.  
  487. {
  488.    int cnt,stick,x,x2,diff,temp;
  489.    static char flop=0;
  490.  
  491.    if (!gs_vb_time())
  492.       return;
  493.    gs_vb_timer_reset();
  494.    for (cnt=0; cnt < CLOUDS; cnt++)
  495.       {
  496.       if (cloud_count[cnt] == cloud_rate[cnt])
  497.          {
  498.          cloud_count[cnt]=0;
  499.          gs_scroll_pvp(&display,&pvp[cnt],cloud_move[cnt],0);
  500.          }
  501.       else
  502.          cloud_count[cnt]++;
  503.       }
  504.    stick = gs_joystick(1);
  505.    if (stick & (JOY_LEFT|JOY_RIGHT))
  506.       {
  507.       if (stick & JOY_LEFT)
  508.          {
  509.          x=-1;
  510.          x2=-SCROLL_SPEED;
  511.          }
  512.       else if (stick & JOY_RIGHT)
  513.          {
  514.          x=1;
  515.          x2=SCROLL_SPEED;
  516.          }
  517.       diff=vp.xoff+x2;
  518.       temp=vp.bmwidth-vp.width;
  519.       if (diff < 0)
  520.          x2=temp+x2;                           /* shift to end of bitmap */
  521.       else if (diff > temp)
  522.          x2=-(temp-x2);                        /* shift to beginning of bitmap */
  523.       gs_scroll_vp_pf1(&display,0,x2,0,1);   /* scroll viewport 0, sync with VB */
  524.       if (flop)
  525.          gs_scroll_pvp(&display,&pvp[CLOUDS],x,0);   /* scroll mountains */
  526.       flop^=1;
  527.       if (x > 0)
  528.          {
  529.          gs_scroll_pvp(&display,&pvp[CLOUDS+1],BOTTOM_SPEED,0);   /* scroll fence */
  530.          gs_spvp_right(&display,&spvp);
  531.          gs_spvp_right(&display,&spvp2);
  532.          }
  533.       else
  534.          {
  535.          gs_scroll_pvp(&display,&pvp[CLOUDS+1],-BOTTOM_SPEED,0);   /* scroll fence */
  536.          gs_spvp_left(&display,&spvp);
  537.          gs_spvp_left(&display,&spvp2);
  538.          }
  539.       }
  540. }
  541.  
  542. /***************************************************************************/
  543.  
  544. int check_close()
  545.  
  546. /* check for user input */
  547.  
  548. {
  549.    if (gs_joystick(0) & (JOY_BUTTON1|JOY_BUTTON2))
  550.       return(1);            /* either mouse button exits */
  551.    return(0);
  552. }
  553.  
  554. /***************************************************************************/
  555.  
  556. void cleanup()
  557.  
  558. /* release all resources and memory */
  559.  
  560. {
  561.    dealloc();
  562.    gs_remove_display(&display);
  563.    gs_close_vb_timer();
  564. }
  565.  
  566. /***************************************************************************/
  567.  
  568. void dealloc()
  569.  
  570. /* release gfx & other memory */
  571.  
  572. {
  573.    int cnt;
  574.  
  575.    if (vp.bitmap1)
  576.       {
  577.       vp.bitmap1->Planes[2]=vp.bitmap1->Planes[4];   /* fix bitmap again */
  578.       vp.bitmap1->Planes[5]=NULL;
  579.       vp.bitmap1->Planes[4]=NULL;
  580.       vp.bitmap1->Planes[3]=NULL;
  581.       vp.bitmap1->Depth=3;
  582.       gs_free_bitmap(vp.bitmap1);
  583.       }
  584.    for (cnt=0; cnt < (PVP_FIELDS-1); cnt++)
  585.       {
  586.       if (pvp[cnt].bitmap[0])
  587.          gs_free_bitmap(pvp[cnt].bitmap[0]);
  588.       }
  589.    if (spvp.bitmap[0])
  590.       gs_free_bitmap(spvp.bitmap[0]);
  591.    if (spvp.list)
  592.       gs_free_spvp(&spvp);
  593.    if (spvp2.list)
  594.       gs_free_spvp(&spvp2);
  595. }
  596.